/*****************************************************************************/
/* File: Utils.h                                                          */
/* Author: rszulgo                                                           */
/*                                                                           */
/* Description:																 */
/*	Class of utils.															 */
/*****************************************************************************/
#pragma once

#include <windows.h>
#include "math.h"
#include <stdio.h>
#include <string>
#include <vector>
#include <gl\gl.h>
#include <gl\glu.h>
#include "Common.h"
#include "TextControl.h"

template<class _T>
struct vec3
{
public:
	union
	{
		struct{
			_T x, y, z;
		};
		_T pos[3];
	};
	vec3<_T>() {};
	vec3<_T>(_T fX, _T fY, _T fZ) 
		: x(fX), y(fY), z(fZ)
	{
	}

	vec3<_T> operator * (float fX)
	{
		vec3<_T> f3R;
		f3R.x = x*fX;
		f3R.y = y*fX;
		f3R.z = z*fX;
		return f3R;
	}

	vec3<_T> operator + (vec3<_T> f3X)
	{
		vec3<_T> f3R;
		f3R.x = x*f3X.x;
		f3R.y = y*f3X.y;
		f3R.z = z*f3X.z;
		return f3R;
	}
	float operator[](int i)
	{
		return pos[i];
	}
	bool operator==(vec3<_T> v)
	{
		return (pos[0]==v.pos[0])&&(pos[1]==v.pos[1])&&(pos[2]==v.pos[2]);
	}

};

typedef vec3<float> float3;
typedef vec3<double> double3;


template<class _T>
struct vec2
{
public:
	union
	{
		struct{
			_T x, y;
		};
		struct{
			_T u, v;
		};
		_T pos[2];
	};
	vec2<_T>() {};
	vec2<_T>(_T fX, _T fY) 
		: x(fX), y(fY)
	{
	}

	vec2<_T> operator * (float fX)
	{
		vec3<_T> f3R;
		f3R.x = x*fX;
		f3R.y = y*fX;
		return f3R;
	}

	vec2<_T> operator + (vec2<_T> f3X)
	{
		vec3<_T> f3R;
		f3R.x = x*f3X.x;
		f3R.y = y*f3X.y;
		return f3R;
	}
	float operator[](int i)
	{
		return pos[i];
	}
	bool operator==(vec2<_T> v)
	{
		return (pos[0]==v.pos[0])&&(pos[1]==v.pos[1]);
	}
};

typedef vec2<float> float2;
typedef vec2<double> double2;

//struct of material for models
struct SMaterial
	{
		double3 d3Diffuse;
		double3 d3Specular;
		double dShiness;
		double dAlpha;

		void operator = (const SMaterial& other)
		{
			d3Diffuse = other.d3Diffuse;
			d3Specular = other.d3Specular;
			dShiness = other.dShiness;
			dAlpha = other.dAlpha;
		}
	};

struct SBMPHeader
{
	unsigned short	ucMagic;
	unsigned int	uiFileSize;
	unsigned int	uiReserved;
	unsigned int	uiImageOffset;
	unsigned int	uiHeaderSize;
	unsigned int	uiWidth;
	unsigned int	uiHeight;
	unsigned short	usBitPlans;
	unsigned short	usBitsPerPixel;
	unsigned int	uiCompression;
	unsigned int	uiImageSize;	//in bytes
	unsigned int	uiHorResolution;
	unsigned int	uiVertResolution;
	unsigned int	uiUsedColors;
	unsigned int	uiMostImportantColor;
};

class CUtils
{
public:
	CUtils(void);
	~CUtils(void);

	static void Vec3Norm(double fVec[3]);
	static void Vec3Mult(double fVec3[3], double fA);
	static double Vec3DotProduct(double fVec3A[3], double fVec3B[3]); 
	static void Vec3Add(double fVec3A[3], double fVec3B[3]); 
	static GLuint LoadRAW(const char* szFileName, int iWidth, int iHeight);	//returns texture ID
	static GLuint LoadBMP(const char* szFileName);	//returns texture ID
	static std::vector<std::string> GetTokens(std::string sParam);		// get tokens of menu item string {keyName, keyValue)
	static std::string AsciiToKeyName(int iChar);
	static int StringToKeyValue(std::string sString);
	static std::vector<std::string> ReadSettings();		// Read settings from file and return values in a vector
	static void SaveSettings(std::vector<CTextControl*>);	// Save settings to file

	static void MulMatrixR(double fMatrDest[16], double fMatrA[16], double fMatrB[16]);		//multiplies two row-major matrices 
	static void MulMatrixC(double fMatrDest[16], double fMatrA[16], double fMatrB[16]);		//multiplies two column-major matrices 

	static void InvertMatrix(double *out, double *m);	//invert column-major matrix
	//multiplies 4x1 vector by 4x4 matrix
	static void TransformVec(double dst[4], const double mat[16], const double vec[4]);

	//converts 3x1 vector to 4x1, by adding "1" as last value, and multiplies it by 4x4 matrix
	static void TransformVec3(double dst[4], const double mat[16], const double vec[4]);
};
